#include "StdAfx.h"
#include "Util.h"

#include <regext.h>
#include <atlbase.h>
#include <cemapi.h>
#include <mapiutil.h>
#include <mapidefs.h>

#include "Settings.h"

#ifdef _DEBUG
#include "crtdbg.h"
#endif

bool CUtil::ParseColor(const TCHAR* val, COLORREF& clr)
{
  if (!val || ::_tcslen(val) < 6)
    return false;

  TCHAR str[7] = { 0 };
  ::_tcsncpy(str, val, 6);
  int b = ::_tcstol(str + 4, NULL, 16);
  str[4] = 0;
  int g = ::_tcstol(str + 2, NULL, 16);
  str[2] = 0;
  int r = ::_tcstol(str, NULL, 16);

  clr = RGB(r, g, b);
  return true;
}

CString CUtil::MakeColor(COLORREF clr)
{
  CString s;
  s.Format(TEXT("%02x%02x%02x"), GetRValue(clr), GetGValue(clr), GetBValue(clr));
  return s;
}

bool CUtil::IsImageFile(const TCHAR* sFile)
{
  static CString   imgTypes[] = { TEXT(".png"), TEXT(".jpg"), TEXT(".jpeg"), TEXT(".gif"), TEXT(".bmp") };
  static const int imgTypesCount = 5;
  
  TCHAR* ext = ::_tcsrchr(sFile, TEXT('.'));
  if (!ext)
    return false;

  for (int i = 0; i < imgTypesCount; i++)
  {
    if (::_tcsicmp(ext, imgTypes[i]) == 0)
      return true;
  }

  return false;
}

bool CUtil::LoadPictureFromFile(IImage** pImage, const TCHAR* sFile)
{
  if (!pImage || !sFile)
    return false;

  HRESULT hr;
  IImagingFactory* pFactory = NULL;

  hr = ::CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&pFactory);
  if (FAILED(hr))
    return false;

  hr = pFactory->CreateImageFromFile(sFile, pImage);
  pFactory->Release();

  return SUCCEEDED(hr);
}

bool CUtil::SavePictureToFile(IImage* pImage, const TCHAR* sFile, EImageFormat format)
{
  if (!pImage || !sFile)
    return false;

  HRESULT hr;
  IImagingFactory* pFactory = NULL;

  hr = ::CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&pFactory);
  if (FAILED(hr))
    return false;

  UINT count;
	ImageCodecInfo* imageCodecInfo = NULL;
  hr = pFactory->GetInstalledEncoders(&count, &imageCodecInfo);
	if (FAILED(hr) || count == 0)
  {
    pFactory->Release();
    return false;
  }

	// Get the particular encoder to use
	CString formatString;
	switch(format)
  {
  case ifPng:
    formatString = TEXT("image/png");
    break;
  case ifGif:
    formatString = TEXT("image/gif");
    break;
  case ifJpeg:
  default:
    formatString = TEXT("image/jpeg");
    break;
  }

  CLSID encoderClassId;
  bool  found = false;

  for(UINT i = 0; i < count; i++)
  {
    if (::_tcscmp(imageCodecInfo[i].MimeType, formatString) == 0)
    {
   	  encoderClassId = imageCodecInfo[i].Clsid;
      found = true;
   		break;
		}
  }
  CoTaskMemFree(imageCodecInfo);

  if (!found)
  {
    pFactory->Release();
    return false;
  }

  IImageEncoder* imageEncoder = NULL;
  hr = pFactory->CreateImageEncoderToFile(&encoderClassId, sFile, &imageEncoder);
	if (FAILED(hr))
  {
    pFactory->Release();
    return false;
  }
	/*
		Call IImageEncoder::GetEncodeSink to retrieve an IImageSink interface. The IImageSink interface is implemented as follows: 
			a. Call IImageSink::BeginSink to negotiate the values contained in the ImageInfo structure for encoding the 
			   current frame. 
			b. Call IImageSink::SetPalette to pass color palette information about the current image frame to the image sink. 
			c. If you need to pass property data to the image sink, you can optionally call IImageSink::GetPropertyBuffer to 
			   obtain a buffer that will contain the property data. 
			d. If GetPropertyBuffer is called above, you must next call IImageSink::PushPropertyItems to transfer the 
			   property data to the image sink. 
			   The buffer that was allocated by GetPropertyBuffer must be deallocated in the implementation for 
			   PushPropertyItems. 
			e. Call IImageSink::PushPixelData or IImageSink::GetPixelDataBuffer to begin the data transfer, depending on how the 
			   image data is stored in the source: 
			   If the image source has allocated memory for the image, use PushPixelData. 
			   If the image source has not allocated memory for the image, use GetPixelDataBuffer. For each call to GetPixelDataBuffer, 
			   IImageSink::ReleasePixelDataBuffer must also be called. 
			f. Call ImageSink::EndSink to complete the encoding process. 
			g. Call ImageSink::Release to free the IImagesink interface. 				
	*/	
				
  IImageSink* imageSink = NULL;
  hr = imageEncoder->GetEncodeSink(&imageSink);
  if (FAILED(hr))
  {
    imageEncoder->Release();
    pFactory->Release();
	  return false;
  }

  hr = pImage->PushIntoSink(imageSink);

  if (SUCCEEDED(hr))
  {
    imageSink->EndSink(S_OK);
  }
  else
  {
    imageSink->EndSink(E_FAIL);
  }

  imageSink->Release();

  imageEncoder->TerminateEncoder();

  imageEncoder->Release();
  pFactory->Release();

  return SUCCEEDED(hr);
}

bool CUtil::GetAppVersion(int& h1, int& h2, int& m1, int& m2)
{
  bool result = false;

  TCHAR szPath[MAX_PATH*2];
  ::GetModuleFileName(NULL, szPath, MAX_PATH*2);

  DWORD dwHandle;
  DWORD dwSize = ::GetFileVersionInfoSize(szPath, &dwHandle);
  if (dwSize > 0)
  {
    LPTSTR pData = (LPTSTR)malloc(dwSize);
    if (pData)
    {
      if (::GetFileVersionInfo(szPath, dwHandle, dwSize, pData))
      {
        UINT uInfoSize = 0;
        VS_FIXEDFILEINFO* pInfo = NULL;
        if (VerQueryValue(pData, TEXT("\\"), (LPVOID*)&pInfo, &uInfoSize))
        {
          h1 = HIWORD(pInfo->dwFileVersionMS);
          h2 = LOWORD(pInfo->dwFileVersionMS);
          m1 = HIWORD(pInfo->dwFileVersionLS);
          m2 = LOWORD(pInfo->dwFileVersionLS);
          result = true;
        }
      }

      free(pData);
    }
  }

  return result;
}

bool CUtil::EnumEmailAccounts(CStringVector& list)
{
  list.clear();

  HRESULT hr;
  CComPtr<IMAPITable> ptbl;
  CComPtr<IMAPISession> pSession;
  SRowSet *prowset = NULL;
  SPropValue  *pval = NULL;

  SizedSPropTagArray (1, spta) = { 1, PR_DISPLAY_NAME };

  // Log onto MAPI
  hr = MAPILogonEx(0, NULL, NULL, 0, static_cast<LPMAPISESSION *>(&pSession));
  if (FAILED(hr))
  {
    return false;
  }

  // Get the table of accounts
  hr = pSession->GetMsgStoresTable(0, &ptbl);
  if (FAILED(hr))
  {
    pSession->Logoff(0, 0, 0);
    return false;
  }
 
  // set the columns of the table we will query
  hr = ptbl->SetColumns ((SPropTagArray *) &spta, 0);
  if (FAILED(hr))
  {
    pSession->Logoff(0, 0, 0);
    return false;  
  }

  while (SUCCEEDED(ptbl->QueryRows (1, 0, &prowset)) && prowset != NULL && prowset->cRows > 0)
  {
    pval = prowset->aRow[0].lpProps;
    list.push_back(CString(pval[0].Value.lpszW));

    // Free the previous row
    FreeProws (prowset);
    prowset = NULL;

  }

  pSession->Logoff(0, 0, 0);
  return list.size() > 0;
}